package org.gc.amino.ia;

import java.awt.geom.Point2D;
import java.io.IOException;
import java.util.List;
import java.util.Random;

import org.apache.log4j.Logger;
import org.gc.amino.engine.Game;
import org.gc.amino.engine.mote.Mote;
import org.gc.amino.engine.terrainmap.PointD;
import org.gc.amino.ia.httpserver.IaDeliveryInterface;
import org.gc.amino.ia.httpserver.IaLauncher;
import org.gc.amino.ia.scalar.ScalarField;
import org.gc.amino.universe.MetaUniverse;
import org.gc.amino.universe.Universe;

/**
 * This AI follows the descending gradient of potential in the field.
 */
public class MonteCarloAI implements IaDeliveryInterface {

	private static final Logger log = Logger.getLogger(StupidIa.class);

	private static final int NumberOfDirections = 8;

	private Random random = new Random();
	private PointD terrainSize;
	private PointD currentDirection = null;
	private PointD[] cardinal_directions;
	private int moving_counter = 0;

	private int idling_counter_max = 20;
	private int idling_counter = idling_counter_max;

	public MonteCarloAI() {
		this.cardinal_directions = new PointD[NumberOfDirections + 1];

		this.cardinal_directions[0] = new PointD(0, 0);
		for (int i = 1; i < NumberOfDirections + 1; ++i) {
			double angle = 2 * Math.PI / i;
			this.cardinal_directions[i] = new PointD(Math.cos(angle),
					Math.sin(angle));
		}
	}

	@Override
	public void init(PointD size) {
		terrainSize = size;
	}

	@Override
	public PointD frame(Mote you, List<Mote> otherMotes) {
		
		int moving_counter_max = 2;

		if (moving_counter > 0) {
			moving_counter--;
			return currentDirection;
		} else if (idling_counter <= 0) {
			moving_counter = moving_counter_max;
			idling_counter = idling_counter_max;

			Universe universe = new Universe(this.terrainSize, otherMotes, you);
			//ScalarField sf = new ScalarField(otherMotes);
			int best_dir = this.findBestDirection(universe);

			MoteSimulator me = universe.getMe();
			PointD best = this.cardinal_directions[best_dir];
			currentDirection = new PointD(me.getPosition().x + me.getSpeed().x
					- best.x, me.getPosition().y + me.getSpeed().y - best.y);

			double dot_product = (best.x * me.getSpeed().x + best.y
					* me.getSpeed().y)
					/ me.getSpeed().distance(0, 0);

			if (dot_product < 0) {
				moving_counter_max = 6;
			} else {
				moving_counter_max = 2;
				if (dot_product > 0.8) {
					currentDirection = null;
				}
			}

			System.out.println("speed: " + me.getSpeed().distance(0, 0));
			return currentDirection;

		} else {
			idling_counter--;
			return null;
		}
	}

	public int findBestDirection(Universe universe) {
		
		MonteCarloTreeNode mctn = new MonteCarloTreeNode();
		mctn.selectAction(new MetaUniverse(universe, 1, 8));
		return mctn.bestMoves().get(0);
		
		/*
		 * int best = 0; Mote2 you = universe.getMe();
		 * 
		 * float probing_dist = you.getRadius();
		 * 
		 * float min_potential = universe.computeFieldPotential(
		 * you.getRadius(), new Point2D.Float( you.getPosition().x +
		 * probing_dist * (float)this.cardinal_directions[0].x,
		 * you.getPosition().y + probing_dist *
		 * (float)this.cardinal_directions[0].y), you);
		 * 
		 * for(int direction = 1; direction < NumberOfDirections + 1;
		 * ++direction) { float potential = universe.computeFieldPotential(
		 * you.getRadius(), new Point2D.Float( you.getPosition().x +
		 * (float)this.cardinal_directions[direction].x, you.getPosition().y +
		 * (float)this.cardinal_directions[direction].y), you); if(potential <
		 * min_potential) { min_potential = potential; best = direction; } }
		 * 
		 * System.out.println("best dir: " + best + " potential: " +
		 * min_potential);
		 * 
		 * return best;
		 */
		//return 0;
	}

	public int iterateMonteCarlo(Mote you, List<Mote> otherMotes) {
		Universe universe = null;
		for (int courage = 0; courage < 10; courage++) {
			universe = new Universe(this.terrainSize, otherMotes, you);
		}
		return 0;
	}

	public static void main(String[] argv) throws IOException {
		IaLauncher.launch(argv, new MonteCarloAI(), 1234);
	}

}
